package com.sinba.common.system.service;

import com.sinba.common.dto.PageDTO;
import com.sinba.common.exception.ApplicationException;
import com.sinba.common.system.dao.EmailMessageQueryDTO;
import com.sinba.common.system.dao.IEmailDAO;
import com.sinba.common.system.dto.EmailMessageDTO;
import com.sinba.common.system.dto.RuleDTO;
import com.sinba.common.system.entity.EmailMessage;

import org.apache.commons.beanutils.BeanUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.activation.DataSource;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

public class EmailService
    implements IEmailService
{
	@Autowired
	private IRuleService ruleService;
    private Session session;
    @Autowired
    private IEmailDAO emailDAO;
    private StringBuffer bodytext = new StringBuffer(  ); // 存放邮件内容

    private String strGet( String str )
    {
        if ( str != null )
        {
            if ( str.indexOf( "<" ) > -1 )
            {
                return str.substring( str.indexOf( "<" ) + 1,
                                      str.indexOf( ">" ) );
            } else{
                return str;
            }
        } else{
            return null;
        }
    }

    /**
        * 读取到的邮件信息转成DTO
        * @param message邮件信息内容
        * @return EmailDTO
        */
    @Transactional
    private EmailMessageDTO entity2Dto( EmailMessage emailMessage )
    {
        EmailMessageDTO dto = new EmailMessageDTO(  );

        try
        {
            BeanUtils.copyProperties( dto, emailMessage );
        } catch ( Exception e )
        {
            e.printStackTrace(  );
        }

        return dto;
    }

    /**
        * 邮件分页查询
        * @param dto:查询条件DTO
        * @param start：查询第几页
        * @param limit:每页行数
        * @return PageDTO??
        */
    @SuppressWarnings( "unchecked" )
    @Transactional
    public PageDTO getEmailMessage( EmailMessageQueryDTO dto, int start, int limit, String sidx, String sord )
    {
        PageDTO p = emailDAO.findPager( dto, start, limit, sidx, sord );
        List<EmailMessage> entities = (List<EmailMessage>) p.getData(  );
        List<EmailMessageDTO> dtos = new ArrayList<EmailMessageDTO>( entities.size(  ) );
        Set<String> emails = new HashSet<String>(  );
        String[] emailStr = null;
        Map<String, String> map = new HashMap<String, String>(  );

        //得到要查询的邮件地址
        for ( EmailMessage entity : entities )
        {
            emails.add( strGet( entity.getFromUser(  ) ) ); //发邮地址
            emails.add( strGet( entity.getToUser(  ) ) ); //接收地址
        }

        //set to string[]
        if ( emails != null )
        {
            emailStr = emails.toArray( new String[emails.size(  )] );

            //map=userInfoService.findUserByEmail(emailStr);
        }

        for ( EmailMessage entity : entities )
        {
            EmailMessageDTO adto = this.entity2Dto( entity );

            if ( ( map != null ) && ( map.get( strGet( entity.getFromUser(  ) ) ) != null ) )
            {
                adto.setFromUser( adto.getFromUser(  ) + "[" + map.get( strGet( adto.getFromUser(  ) ) ) + "]" );
            }

            dtos.add( adto );
        }

        p.setData( dtos );

        return p;
    }

    /**
    * 邮件发�?并保存到数据库中作为已发送的邮件
    * @param dto
    * @throws AddressException
    * MessagingException,IOException
    */
    public boolean sendMail( String email, String title, String content )
    {
        boolean result = false;
        RuleDTO ruleDTO = ruleService.findRuleInfo();
        this.mailSmtpConnection(ruleDTO);

        String mailtype = "text/html;charset=GBK";
        try
        {
            MimeMessage msg = new MimeMessage( session );
//            msg.setFrom(new InternetAddress(dto.getFrom()));
            //设置发件人姓�?姓名<email@email.com>)
            msg.setFrom( new InternetAddress( ruleDTO.getRule004(),
                                              MimeUtility.encodeText(ruleDTO.getRule008(), "gb2312", "b" ) ) );

            InternetAddress[] tos = new InternetAddress[] { new InternetAddress( email ) };

            msg.setRecipients( RecipientType.TO, tos );
            msg.setSubject( title );
            msg.setSentDate( new Date(  ) );

            MimeMultipart multipart = new MimeMultipart( "mixed" );
            BodyPart msgBodyPart = new MimeBodyPart(  );
            multipart.addBodyPart( msgBodyPart );

            BodyPart attBodyPart;
            DataSource ds;
            msg.setContent( multipart );
            msg.setContent( changeUTF8Space(content), mailtype );
            Transport.send( msg );
            //saveEmailMessages(emailMessage);
            result = true;
        } catch ( Exception e )
        {
            result = false;
        	e.printStackTrace();
//            throw new ApplicationException("ERROR_EMAIL_ACCOUNT_ERROR\n",e);
        }

        return result;
    }

    /**
     * 获得邮件正文内容
     *
     * @return String
     */
    public String getBodyText(  )
    {
        return bodytext.toString(  );
    }

    /**
     * 解析邮件，把得到的邮件内容保存到StringBuffer对象中，解析邮件 主要是根据MimeType类型的不同执行不同的操作，一步一步的解析
     *
     * @return void
     */
    public void getMailContent( Part part )
                        throws Exception
    {
        bodytext = new StringBuffer(  );

        String contenttype = part.getContentType(  );

        int nameindex = contenttype.indexOf( "name" );
        boolean conname = false;

        if ( nameindex != -1 )
        {
            conname = true;
        }

        if ( part.isMimeType( "text/plain" ) && ! conname )
        {
            String content = null;

            try
            {
                content = (String) part.getContent(  );
            } catch ( Exception ex )
            {
                String charset = contenttype.substring( contenttype.indexOf( "=" ) + 1 );
                InputStream is = part.getInputStream(  );
                byte[] bs = new byte[is.available(  )];
                is.read( bs );
                content = ( new String( bs, charset ) ).trim(  );
            }

            bodytext.append( content );
        } else if ( part.isMimeType( "text/html" ) && ! conname )
        {
            String content = (String) part.getContent(  ).toString(  );

            if ( contenttype.indexOf( "charset" ) < 0 )
            {
                InputStream is = part.getInputStream(  );
                byte[] bs = new byte[is.available(  )];
                is.read( bs );
                content = ( new String( bs, "GBK" ) ).trim(  );
            }

            bodytext.append( content );
        } else if ( part.isMimeType( "multipart/*" ) )
        {
            Multipart multipart = (Multipart) part.getContent(  );
            int counts = multipart.getCount(  );

            if ( isContainAttach( part ) )
            {
                getMultipartMimeTypeMailContent( multipart.getBodyPart( 0 ) );
            } else
            {
                for ( int i = 0; i < counts; i++ )
                {
                    getMailContent( multipart.getBodyPart( i ) );
                }
            }
        } else if ( part.isMimeType( "message/rfc822" ) )
        {
            getMailContent( (Part) part.getContent(  ) );
        }
    }

    public void getMultipartMimeTypeMailContent( Part part )
                                         throws Exception
    {
        bodytext = new StringBuffer(  );

        String contenttype = part.getContentType(  );

        int nameindex = contenttype.indexOf( "name" );
        boolean conname = false;

        if ( nameindex != -1 )
        {
            conname = true;
        }

        if ( part.isMimeType( "text/plain" ) && ! conname )
        {
            String content = null;

            try
            {
                content = (String) part.getContent(  );
            } catch ( Exception ex )
            {
                String charset = contenttype.substring( contenttype.indexOf( "=" ) + 1 );
                InputStream is = part.getInputStream(  );
                byte[] bs = new byte[is.available(  )];
                is.read( bs );
                content = ( new String( bs, charset ) ).trim(  );
            }

            bodytext.append( content );
        } else if ( part.isMimeType( "text/html" ) && ! conname )
        {
            String content = (String) part.getContent(  ).toString(  );

            if ( contenttype.indexOf( "charset" ) < 0 )
            {
                InputStream is = part.getInputStream(  );
                byte[] bs = new byte[is.available(  )];
                is.read( bs );
                content = ( new String( bs, "GBK" ) ).trim(  );
            }

            bodytext.append( content );
        } else if ( part.isMimeType( "multipart/*" ) )
        {
            Multipart multipart = (Multipart) part.getContent(  );

            //System.out.println("=============内容1�?+multipart.getBodyPart(1).getContent().toString()+"===============");
            bodytext.append( multipart.getBodyPart( 1 ).getContent(  ).toString(  ) );
        } else if ( part.isMimeType( "message/rfc822" ) )
        {
            getMailContent( (Part) part.getContent(  ) );
        }
    }

    /**
     * 读取邮件信息转成Entity
     *
     * @param emessage
     *            :邮件信息内容
     * @return EmailDAP
     */
    private EmailMessage mime2Entity( MimeMessage message, String folderName, String userName )
    {
        EmailMessage dao = new EmailMessage(  );

        try
        {
            getMailContent( message );

            dao.setContent( getBodyText(  ) ); // 内容'
            dao.setDescription( message.getDescription(  ) );

            dao.setSubject( message.getSubject(  ) );
            userName = "<" + userName + ">";

            if ( folderName.equals( "INBOX" ) )
            {
                dao.setFolderName( "INBOX" );
                dao.setReceiveDate( message.getSentDate(  ) );
                dao.setFromUser( this.getFrom( message ) );

                dao.setToUser( userName );
            } else
            {
                dao.setFolderName( "OUTBOX" );
                dao.setToUser( this.getMailAddress( message, "TO" ) );
                dao.setCc( this.getMailAddress( message, "CC" ) );
                dao.setBcc( this.getMailAddress( message, "BCC" ) );
                dao.setSendDate( new Date(  ) );
                dao.setFromUser( this.getFrom( message ) );
            }
        } catch ( Exception e )
        {
            // throw new ApplicationException("ERROR_SCANEMAILMESSAGE\n" + e,e);
            System.out.println( "::::::::::::::::::::::::::get email content error." );
        }

        return dao;
    }

    /**
     * 判断此邮件是否包含附�?
         * @return boolean
     */
    public boolean isContainAttach( Part part )
                            throws Exception
    {
        boolean attachflag = false;

        if ( part.isMimeType( "multipart/*" ) )
        {
            Multipart mp = (Multipart) part.getContent(  );

            for ( int i = 0; i < mp.getCount(  ); i++ )
            {
                BodyPart mpart = mp.getBodyPart( i );
                String disposition = mpart.getDisposition(  );

                if ( ( disposition != null ) &&
                         ( ( disposition.equals( Part.ATTACHMENT ) ) || ( disposition.equals( Part.INLINE ) ) ) )
                {
                    attachflag = true;
                } else if ( mpart.isMimeType( "multipart/*" ) )
                {
                    attachflag = isContainAttach( (Part) mpart );
                } else
                {
                    String contype = mpart.getContentType(  );

                    if ( contype.toLowerCase(  ).indexOf( "application" ) != -1 )
                    {
                        attachflag = true;
                    }

                    if ( contype.toLowerCase(  ).indexOf( "name" ) != -1 )
                    {
                        attachflag = true;
                    }
                }
            }
        } else if ( part.isMimeType( "message/rfc822" ) )
        {
            attachflag = isContainAttach( (Part) part.getContent(  ) );
        }

        return attachflag;
    }

    /**
     * 获得邮件的收件人，抄送，和密送的地址和姓名，根据????递的参数的不??"to"----收件??"cc"---�??人地??"bcc"---�??人地??
     */
    public String getMailAddress( MimeMessage mimeMessage, String type )
                          throws Exception
    {
        String mailaddr = "";
        String addtype = type.toUpperCase(  );
        InternetAddress[] address = null;

        if ( addtype.equals( "TO" ) || addtype.equals( "CC" ) || addtype.equals( "BCC" ) )
        {
            if ( addtype.equals( "TO" ) )
            {
                address = (InternetAddress[]) mimeMessage.getRecipients( Message.RecipientType.TO );
            } else if ( addtype.equals( "CC" ) )
            {
                address = (InternetAddress[]) mimeMessage.getRecipients( Message.RecipientType.CC );
            } else
            {
                address = (InternetAddress[]) mimeMessage.getRecipients( Message.RecipientType.BCC );
            }

            if ( address != null )
            {
                for ( int i = 0; i < address.length; i++ )
                {
                    String email = address[i].getAddress(  );

                    if ( email == null )
                    {
                        email = "";
                    } else
                    {
                        email = MimeUtility.decodeText( email );
                    }

                    String personal = address[i].getPersonal(  );

                    if ( personal == null )
                    {
                        personal = "";
                    } else
                    {
                        personal = MimeUtility.decodeText( personal );
                    }

                    String compositeto = personal + "<" + email + ">";
                    mailaddr += ( "," + compositeto );
                }

                mailaddr = mailaddr.substring( 1 );
            }
        } else
        {
            throw new Exception( "Error emailaddr type!" );
        }

        return mailaddr;
    }

    /**
     * 获得发件人的地址和姓??
             *
     * @return String
     */
    public String getFrom( MimeMessage message )
                   throws Exception
    {
        InternetAddress[] address = (InternetAddress[]) message.getFrom(  );
        String from = address[0].getAddress(  );

        if ( from == null )
        {
            from = "";
        }

        String personal = address[0].getPersonal(  );

        if ( personal == null )
        {
            personal = "";
        }

        String fromaddr = personal + "<" + from + ">";

        return fromaddr;
    }

    /**
     * 将entity EmailMessage和affachment保存入数据库
     *
     * @param EmailConnectionDTO
     */
    @Transactional
    public Long saveEmailMessages( EmailMessage emailMessage )
    {
        emailMessage = emailDAO.merge( emailMessage );

        return emailMessage.getEmailMessageId(  );
    }

    /**
     * 邮件连接创建初始�?
         * @param dto 邮件连接帐号信息DTO
     * @return void
     */
    public void mailSmtpConnection(final RuleDTO ruleDTO)
    {
        Properties pros = new Properties(  );
        /*pros.setProperty("mail.smtp.starttls.enable","true"); 
        pros.setProperty("mail.smtp.EnableSSL.enable","true");*/
        if(ruleDTO.getRule004().indexOf("gmail.com")>-1){
        	pros.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");   
            pros.setProperty("mail.smtp.socketFactory.fallback", "false");   
            pros.setProperty("mail.smtp.port", "465"); 
        }else{
        	 pros.setProperty( "mail.smtp.port", String.valueOf( 25 ) );
        }
          
       
        pros.setProperty("mail.smtp.socketFactory.port", "465");  
        pros.setProperty( "mail.transport.protocol", "smtp" );
        pros.setProperty( "mail.smtp.auth", "true" );
        pros.setProperty( "mail.host", ruleDTO.getRule003());
        
        
        session =
            Session.getInstance( pros,
                                 new Authenticator(  )
                {
                    protected PasswordAuthentication getPasswordAuthentication(  )
                    {
                        return new PasswordAuthentication( ruleDTO.getRule004(), ruleDTO.getRule005() );
                    }
                } );
        session.setDebug( false );
    }

    public void deleteEmail( Long[] ids )
    {
        emailDAO.deleteByIds( ids );
    }
    public final static byte bytes[] = {(byte) 0xC2,(byte) 0xA0};
    public final static String charset = "UTF-8";
    public final static String spaceChar =  "&nbsp;";
	public String changeUTF8Space(String currentStr){
		try {
			if (currentStr != null) {
		        String utfSpace = new String(bytes,charset);
				currentStr = currentStr.replaceAll(utfSpace,spaceChar);
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
        return currentStr;
    }
}
